package io.mft.commons.ioc;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.hutool.core.util.ObjectUtil;
/**
 * API接口spring实例获取工具
 * @类型名称：MapperSpringUtil
 * @说明：TODO
 * @创建者: 胡常建  
 * @创建时间: 2018年3月14日 下午2:53:01
 * @修改者: 胡常建  
 * @修改时间: 2018年3月14日 下午2:53:01
 */
public class MFTSpringUtil{
	static Logger logger=LoggerFactory.getLogger(MFTSpringUtil.class);
	static String PATH="pluginApplication.xml";
	static Map<ClassLoader, ApplicationContext> contexts=new ConcurrentHashMap<ClassLoader, ApplicationContext>();
	/**
	 * 通过类加载起初始化spring 上下文
	 * @说明: TODO
	 * @方法名称: initApplicationContext
	 * @参数 
	 * @返回类型 void    
	 * @创建者: 胡常建  
	 * @创建时间: 2021年2月18日 下午5:41:54
	 * @修改者: 胡常建  
	 * @修改时间: 2021年2月18日 下午5:41:54
	 */
	public static void initApplicationContext() {
		ClassLoader loader=Thread.currentThread().getContextClassLoader();
		initApplicationContext(loader);
	}
	public static void registerApplicationContext(ClassLoader loader,ApplicationContext applicationContext) {
		contexts.put(loader, applicationContext);
	}
	public static void initApplicationContext(ClassLoader loader) {
		if (!contexts.containsKey(loader)) {
			synchronized (contexts) {
				if (!contexts.containsKey(loader)) {
					ApplicationContext applicationContext = new ClassPathXmlApplicationContext(PATH);
					//logger.info("类加载器:{}-加载器hashcode:{}-初始化完成IOC容器->>>框架容器总数量:{}",loader.getClass().getName(),loader.hashCode(),contexts.size());
					contexts.put(loader, applicationContext);
					//logger.info("类加载器:{}-加载器hashcode:{}-初始化完成IOC容器->>>框架容器总数量:{}",loader.getClass().getName(),loader.hashCode(),contexts.size());
				}
			}
		}
		
	}
	
	
    public static <T> T registerBean(String beanId,Class<T> classType) {
    	ClassLoader loader=MFTSpringUtil.class.getClassLoader();
        return registerBean(loader, beanId, classType);
    }
    public static <T> T registerBean(ClassLoader loader,String beanId,Class<T> classType) {
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)getApplicationContext(loader).getAutowireCapableBeanFactory();
        BeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClassName(classType.getName());
        beanFactory.registerBeanDefinition(beanId, beanDefinition);
       // beanFactory.registerSingleton(beanName, singletonObject);
        return getInstance(loader,beanId, classType);
    }
    public static <T> T registerBean(ClassLoader loader,String beanId,T bean) {
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)getApplicationContext(loader).getAutowireCapableBeanFactory();
        beanFactory.registerSingleton(beanId, bean);
        return bean;
    }
    public static <T> T registerBean(String beanId,T bean) {
    	ClassLoader loader=Thread.currentThread().getContextClassLoader();
        return registerBean(loader, beanId, bean);
    }
    public static boolean containsBeanDefinition(ClassLoader loader,String beanId) {
    	DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)getApplicationContext(loader).getAutowireCapableBeanFactory();
    	return beanFactory.containsBeanDefinition(beanId);
	}
    public static <T> T registerBean(ClassLoader loader,String beanId,BeanDefinition beanDefinition) {
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)getApplicationContext(loader).getAutowireCapableBeanFactory();
        beanFactory.registerBeanDefinition(beanId, beanDefinition);
        Object t=getApplicationContext(loader).getBean(beanId);
        return (T)t;
    }
	public static ApplicationContext getApplicationContext() {
		ClassLoader loader=Thread.currentThread().getContextClassLoader();
		return contexts.get(loader);
	}
	public static ApplicationContext getApplicationContext(ClassLoader loader) {
		return contexts.get(loader);
	}
    /**
     * 获取对象 这里重写了bean方法，起主要作用
     * example: getBean("userService")//注意： 类名首字母一定要小写！
     */
	public static <T> T getInstance(String beanId,Class<T> classType) throws BeansException {
        T object= getApplicationContext().getBean(beanId,classType);
        return object;
	}
	public static <T> T getInstance(ClassLoader loader,String beanId,Class<T> classType) throws BeansException {
        T object= getApplicationContext(loader).getBean(beanId,classType);
        return object;
	}
	public static <T> T getInstance(String sysNo,String aliasId,Class<T> classType) throws BeansException {
		ClassLoader loader=MFTSpringUtil.class.getClassLoader();
    	return getInstance(loader, sysNo, aliasId, classType);

    }
	public static <T> T getInstance(ClassLoader loader,String sysNo,String aliasId,Class<T> classType) throws BeansException {
    	String id=sysNo;
		if (!ObjectUtil.isEmpty(aliasId)) {
			id+="."+aliasId;
		}
		return getInstance(loader,id, classType);

    }
	
	public static <T> T getBean(String sysNo, Class<T> classType) {
		StringBuilder builder=new StringBuilder(sysNo);
		builder.append(".");
		builder.append(classType.getSimpleName());
		return getInstance(builder.toString(), classType);
	}
	public static <T> T getBean(String sysNo,String annotationBeanId, Class<T> classType) {
		StringBuilder builder=new StringBuilder(sysNo);
		if (!ObjectUtil.isEmpty(annotationBeanId)) {
			builder.append(".");
			builder.append(annotationBeanId);
		}
		builder.append(".");
		builder.append(classType.getSimpleName());
		return getInstance(builder.toString(), classType);
	}
	
	public static void closeApplicationContext(ClassLoader loader) {
		ApplicationContext applicationContext=getApplicationContext(loader);
		AbstractApplicationContext  context=(AbstractApplicationContext)applicationContext;
		context.close();
		contexts.remove(loader);
	}
}
